package helper

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/slclub/go-tips"
	"math"
	"net"
	"strconv"
	"strings"
	"unicode"
)

var APP_PATH string
var CONFIG_FILE = "/conf/conf.yaml"

func init() {
	APP_PATH = tips.GetRootPath()
}

func GetOutBoundIP() (ip string, err error) {
	conn, err := net.Dial("udp", "8.8.8.8:53")
	if err != nil {
		fmt.Println(err)
		return
	}
	localAddr := conn.LocalAddr().(*net.UDPAddr)
	//fmt.Println(localAddr.String(), "===")
	ip = strings.Split(localAddr.String(), ":")[0]
	//fmt.Println("ip:", ip)
	return
}

func MapStringToAny(um map[string]string) map[string]any {
	if um == nil {
		return map[string]any{}
	}
	rtn := map[string]any{}
	for key, val := range um {
		rtn[key] = val
	}
	return rtn
}

func Camel2Case(name string) string {
	buffer := bytes.NewBuffer([]byte{})
	for i, r := range name {
		if unicode.IsUpper(r) {
			if i != 0 {
				buffer.WriteString("_")
			}
			buffer.WriteRune(unicode.ToLower(r))
		} else {
			buffer.WriteRune(r)
		}
	}
	return buffer.String()
}

// 下划线写法转为驼峰写法
func Case2Camel(name string) string {
	name = strings.Replace(name, "_", " ", -1)
	name = strings.Title(name)
	return strings.Replace(name, " ", "", -1)
}

func Ipv4ToLong(ip string) (uint, error) {
	p := net.ParseIP(ip).To4()
	if p == nil {
		return 0, errors.New("invalid ipv4 format")
	}

	return uint(p[0])<<24 | uint(p[1])<<16 | uint(p[2])<<8 | uint(p[3]), nil
}

func LongToIpv4(i uint) (string, error) {
	if i > math.MaxUint32 {
		return "", errors.New("beyond the scope of ipv4")
	}

	ip := make(net.IP, net.IPv4len)
	ip[0] = byte(i >> 24)
	ip[1] = byte(i >> 16)
	ip[2] = byte(i >> 8)
	ip[3] = byte(i)

	return ip.String(), nil
}

func ConvMapAnyToMapString(m *map[string]interface{}) map[string]string {
	rtn := make(map[string]string)
	for k, v := range *m {
		switch rv := v.(type) {
		case int:
			rtn[k] = strconv.FormatInt(int64(rv), 10)
		case int64:
			rtn[k] = strconv.FormatInt(int64(rv), 10)
		case float64, float32:
			vv, _ := v.(float64)
			rtn[k] = strconv.FormatFloat(vv, 'G', 30, 64)

		case string:
			vv, _ := v.(string)
			rtn[k] = vv
		}
	}
	return rtn
}

func ConvMapStringToMapAny(m map[string]string) map[string]any {
	rtn := make(map[string]any)
	for k, v := range m {
		rtn[k] = v
	}
	return rtn
}

func TailTrimEmptyBack(str string) string {
	n := len(str)

	if n == 0 {
		return str
	}

	str = strings.ReplaceAll(str, "\t", "")
	n = len(str)
	if str[n-2:] == "\r\n" {
		return str[:n-2]
	}
	if str[n-2:] == "\t\n" {
		return str[:n-2]
	}
	if str[n-1:] == "\n" {
		return str[:n-1]
	}
	return str
}

func HmacSHA1UTF8(value string, secret string) string {
	h := hmac.New(sha1.New, []byte(secret))
	h.Write([]byte(value))
	hmacSign := base64.StdEncoding.EncodeToString(h.Sum(nil))

	return hmacSign
}
